ItIron2021
Javascript
對點進來的你說一下,恭喜你撐到今天! 非同步的最後一個問題,之後的最後幾天就會進入到一些比較零碎的應用題目囉! 馬上來看一下最後的非同步題目吧! 順帶一提,這個題目我後來才發現原來是之前在it邦的另一個鐵人賽系列文就有看過了..面試官可以不要直接把看到的題目拿來考嗎,至少換個例子吧! 文章連結我會附在最後,是個非常棒的系列文!
請問下方的程式碼輸出結果為?
setTimeout(() => alert("timeout"));
Promise.resolve()
.then(() => alert("promise"));
alert("global ex. context");
看到這邊你應該迫不及待的要回答了,這很簡單嘛!
阿不就考同步 VS 非同步的執行順序,event loop我被虐了幾次了還不懂嗎?
先處理同步程式碼再處理非同步就好了嘛! 跳出的alert順序肯定是這樣的!
global ex. context
timeout
promise
但實際上卻是....
global ex. context
promise
timeout
你現在的心情大概是這樣吧,我懂
其實原因是因為瀏覽器在處理非同步時其實還有細節我們之前沒有提到,就是所謂的macro task & micro task,這兩個名詞中文老樣子沒有我特別滿意的翻譯(許多人叫宏任務&微任務,但..我聽不習慣),下面還是就用原文來說明吧!
老樣子解釋觀念不是我的重點,這邊只是簡單的說明!
實際上瀏覽器在執行程式碼時會是以下的流程
簡單來說就是分同步任務又再細分為macro task & micro task
常見的macro task有
而常見的micro task有
兩種任務的執行時間點並不相同,每執行完一個macro task,它就會停下來看一下micro task queue中是不是有還沒執行的micro task並一口氣將全部的micro task執行完! 接著在繼續跑渲染之類的流程後再次執行下一個macro task,並反覆這樣的流程,所以簡單來說
可在一次的event loop就執行多個micro task,但只能執行一個macro task
所以只要能分辨macro task/micro task就沒有問題囉! 理解這點之後回頭看一下題目,promise取值很明顯屬於micro、而setTimeout屬於macro,但別忘記執行script也算一個macro task,也就是說流程是這樣的
run script (跑完一個macro task,該清空micro task queue了)
=> promise (清空micro task queue,該跑下一個macro task了)
=> setTimeout
最終就造成你看到的結果囉,是不是沒有想像中這麼難懂呢?
今天會附上兩篇很棒的文章,若想進一步了解相關觀念或題目我是非常推薦的!
macro task vs micro task、event loop
JS 原力覺醒Day15 - Macrotask 與MicroTask
聊聊JavaScript非同步中的macrotask和microtask
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!